package queues

import (
	"fmt"
	"github.com/goravel/framework/facades"
	"github.com/goravel/framework/support/path"
	"github.com/spf13/cast"
	"goravel/app/models"
	Services "goravel/app/services"
	Ftp "goravel/packages/ftpclient"
	SFtp "goravel/packages/sftpclient"
	"goravel/packages/socket/servers"
	"os"
)

type DownloadParseService struct {
	parseBatchService *Services.BatchService
}

func (r DownloadParseService) NewDownloadParseService() *DownloadParseService {
	return &DownloadParseService{}
}

func (r *DownloadParseService) DownloadParseStart() {
	fmt.Println("DownloadParseService==Start")
	var configurations []models.Configuration
	facades.Orm().Query().Where("active", 1).Find(&configurations)
	for _, configuration := range configurations {
		var user models.User
		facades.Orm().Query().Where("id", configuration.UserID).Find(&user)
		if user.ID != 0 {
			fmt.Println("DownloadParseService==downloadTask")
			err, _ := r.downloadTask(user, configuration, configuration.Port, configuration.Host, configuration.Username, configuration.Password, configuration.Type)
			if err != nil {
				fmt.Println(err)
			} else {
				fmt.Println("DownloadParseService==parseTask")
				r.parseTask(configuration, user)
			}
		}
	}
}

// 1)下载task
/**
port := ctx.Request().Input("port")
hostname := ctx.Request().Input("host")
username := ctx.Request().Input("username")
password := ctx.Request().Input("password")
type_name := ctx.Request().Input("type")
*/
func (r *DownloadParseService) Notice(user models.User, message string) {
	var stage = "D:notice"
	nclient_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
	servers.SendMessage2Client(nclient_id, cast.ToString(user.ID), 200, message, &stage)
}
func (r *DownloadParseService) downloadTask(user models.User, config models.Configuration, port string, hostname string, username string, password string, type_name string) (error, string) {
	if type_name == "ftp" {
		r.Notice(user, "FTP连接初始化中...")
		client, err := Ftp.NewClient(hostname+":"+port, username, password)
		if client != nil {
			defer client.Close()
		}
		if err != nil {
			facades.Log().Info("ftp->下载连接失败:", hostname+":"+port, username, password)
			r.Notice(user, "FTP连接初始化失败...")
			return err, err.Error()
		}
		storePath := path.Public(type_name + "/" + hostname + "/" + port + "/" + username)
		//文件夹：根据结构host/port/username创建文件夹
		r.Notice(user, "创建保存文件夹...")
		_, err_dir := client.MkdirIfNotExisted(storePath)
		if err_dir != nil {
			facades.Log().Info("ftp->创建文件夹失败:", storePath)
			r.Notice(user, "本地文件夹创建失败:")
			return err_dir, "ftp->创建文件夹失败"
		}

		r.Notice(user, "正在检索目标文件夹，请稍后...")
		pathList, _ := client.WalkDir("Logs", "")
		remotePath := ""
		if len(pathList) > 0 {
			remotePath = pathList[0]
		} else {
			r.Notice(user, "未找到文件目标文件夹，请检查...")
			return nil, "未找到文件"
		}
		files, err := client.FindFile(remotePath)
		for index, v := range files {
			//1、下载过，且完全一样，跳过
			//去重：查询其他相同，但是文件大小不同的记录，删除
			var downloadRecord models.DownloadRecord
			facades.Orm().Query().
				Where("user_id", user.ID).
				Where("configuration_id", config.ID).
				Where("file_size", v.Size).
				Where("file_name", v.Name).
				First(&downloadRecord)
			if downloadRecord.ID != 0 {
				//说明下载过，将状态更新为不需要下载
				facades.Orm().Query().Model(&downloadRecord).Update("is_need_download_and_parse", 0)
				r.Notice(user, fmt.Sprintf("第%d个下载完成，%s请稍后...\n|(%d:%d)", index+1, v.Name, index+1, len(files)))
				fmt.Printf("第%d个，%s下载完成\n", index, v.Name)
				continue
			} else {
				//没有文件，下载，并记录
				r.Notice(user, fmt.Sprintf("第%d个有差异，重新下载，%s请稍后...\n|(%d:%d)", index+1, v.Name, index+1, len(files)))
				os.Remove(storePath + "/" + v.Name)
				//再次下载
				client.SaveFile(remotePath+"/"+v.Name, storePath+"/"+v.Name)
				//msg := fmt.Sprintf("D:%d:%d:%s", index+1, len(files), v.Name)
				//client_id := facades.Cache().GetString(fmt.Sprintf("user:%d", user.ID)) // 获取缓存
				//servers.SendMessage2Client(client_id, cast.ToString(user.ID), 200, "D:working", &msg)
				//创建下载记录
				facades.Orm().Query().Create(&models.DownloadRecord{
					FileName:               v.Name,
					FilePath:               remotePath + "/" + v.Name,
					FileSize:               cast.ToUint64(v.Size),
					CurrentOrder:           index + 1,
					UserID:                 user.ID,
					ConfigurationID:        config.ID,
					IsNeedDownloadAndParse: 1,
				})
			}

		}
	} else {
		r.Notice(user, "SFTP连接初始化中...")
		sftp_client, err := SFtp.NewSftpClient(hostname+":"+port, username, password)
		if sftp_client != nil {
			defer sftp_client.Close()
		}

		if err != nil {
			facades.Log().Info("sftp->下载连接失败:", hostname+":"+port, username, password)
			r.Notice(user, "SFTP连接初始化失败...")
			return err, err.Error()
		}
		storePath := path.Public(type_name + "/" + hostname + "/" + port + "/" + username)
		//文件夹：根据结构host/port/username创建文件夹
		r.Notice(user, "创建保存文件夹...")
		_, err_dir := sftp_client.MkdirIfNotExisted(storePath)
		if err_dir != nil {
			r.Notice(user, "本地文件夹创建失败...")
			facades.Log().Info("sftp->创建文件夹失败:", storePath)
			return err_dir, err_dir.Error()
		}

		r.Notice(user, "正在检索目标文件夹，请稍后...")
		pathList, _ := sftp_client.WalkDir("Logs", "")
		remotePath := ""
		if len(pathList) > 0 {
			remotePath = pathList[0]
		} else {
			r.Notice(user, "未找到文件目标文件夹，请检查...")
			return nil, "未找到文件"
		}

		//获取远程文件列表
		files, err := sftp_client.FindFile(remotePath)
		r.Notice(user, "正在获取目标文件，请稍后...")
		for index, v := range files {
			//1、2种情况，1是所有信息都相同，不下载直接跳过，2是文件名相同，但是文件大小不同，删除原来的文件，重新下载
			//去重：查询其他相同，但是文件大小不同的记录，删除
			var downloadRecord models.DownloadRecord
			facades.Orm().Query().
				Where("user_id", user.ID).
				Where("configuration_id", config.ID).
				Where("file_size", v.Size()).
				Where("file_name", v.Name()).
				First(&downloadRecord)
			if downloadRecord.ID != 0 {

				//说明下载过，将状态更新为不需要下载
				facades.Orm().Query().Model(&downloadRecord).Update("is_need_download_and_parse", 0)
				//跳过
				r.Notice(user, fmt.Sprintf("第%d个下载完成，%s请稍后...\n|(%d:%d)", index+1, v.Name(), index+1, len(files)))
				continue
			} else {
				//该文件可能存在，可能不存在，去重：删除真实文件
				os.Remove(storePath + "/" + v.Name())
				r.Notice(user, fmt.Sprintf("第%d个有差异，重新下载，%s请稍后...\n|(%d:%d)", index+1, v.Name(), index+1, len(files)))
				//再次下载
				sftp_client.SaveFile(remotePath+"/"+v.Name(), storePath+"/"+v.Name())
				fmt.Printf("第%d个，%s下载完成\n", index, v.Name())
				//创建下载记录
				facades.Orm().Query().Create(&models.DownloadRecord{
					FileName:               v.Name(),
					FilePath:               remotePath + "/" + v.Name(),
					FileSize:               cast.ToUint64(v.Size()),
					CurrentOrder:           index + 1,
					UserID:                 user.ID,
					ConfigurationID:        config.ID,
					IsNeedDownloadAndParse: 1,
				})
			}

		}
	}
	return nil, ""
}

// 2)解析task
func (r *DownloadParseService) parseTask(configuration models.Configuration, user models.User) {
	r.Notice(user, "解析任务启动中...")
	foldPath := r.getPath(configuration)
	facades.Log().Info("解析任务启动中(文件夹）...", foldPath)
	batchService := r.parseBatchService.NewBatchService()
	batchService.ParseActionAll(foldPath, configuration.ID)
}

// 返回文件夹路径和配置id
func (r *DownloadParseService) getPath(configuration models.Configuration) string {
	foldPath := configuration.Type + "/" + configuration.Host + "/" + configuration.Port + "/" + configuration.Username + "/"
	return foldPath
}
